package com.bsj.travel.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bsj.travel.constant.NumericalConstants;
import com.bsj.travel.def.common.DO.MenuDO;
import com.bsj.travel.def.common.DO.RoleDO;
import com.bsj.travel.def.common.DO.RoleMenuDO;
import com.bsj.travel.def.common.DO.UserDO;
import com.bsj.travel.def.common.DTO.web.role.RoleDTO;
import com.bsj.travel.def.common.DTO.web.role.RoleSearchDTO;
import com.bsj.travel.def.common.VO.RoleVO;
import com.bsj.travel.def.global.JsonResult;
import com.bsj.travel.def.global.JsonResultEnum;
import com.bsj.travel.exception.ApiException;
import com.bsj.travel.mapper.mysql.MenuMapper;
import com.bsj.travel.mapper.mysql.RoleMapper;
import com.bsj.travel.mapper.mysql.RoleMenuMapper;
import com.bsj.travel.mapper.mysql.UserMapper;
import com.bsj.travel.system.service.MenuService;
import com.bsj.travel.system.service.SysRoleService;
import com.bsj.travel.util.DataUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/***
 * @description SysRoleServiceImpl
 * @author LiJiaXin
 * @version 1.0.0
 * @time 2024/1/11 16:45
 **/
@Service
public class SysRoleServiceImpl implements SysRoleService {

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private MenuService menuService;

    /**
     * 添加角色
     *
     * @param roleDTO
     * @return com.bsj.travel.def.global.JsonResult
     * @author ljx
     * @time 2024/1/11 17:35
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult addRole(RoleDTO roleDTO) {
        paramCheck(roleDTO);
        RoleDO roleDO = new RoleDO();
        BeanUtils.copyProperties(roleDTO, roleDO);
        if (roleMapper.insert(roleDO) > 0) {
            batchInsertRoleMenu(roleDTO.getMenuIds(), roleDO.getId());
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 批量添加角色与权限的关系
     *
     * @param menuIds
     * @param roleId
     * @return void
     * @author ljx
     * @time 2024/1/12 11:57
     */
    private void batchInsertRoleMenu(List<Integer> menuIds, Integer roleId) {
        List<RoleMenuDO> roleMenuDOS = menuIds.stream().map(menuId -> {
            RoleMenuDO roleMenuDO = new RoleMenuDO(roleId, menuId);
            return roleMenuDO;
        }).collect(Collectors.toList());
        roleMenuMapper.batchInsert(roleMenuDOS);
    }

    /**
     * 参数校验
     *
     * @param roleDTO
     * @return void
     * @author ljx
     * @time 2024/1/12 10:15
     */
    private void paramCheck(RoleDTO roleDTO) {
        //去重校验
        RoleSearchDTO roleSearchDTO = new RoleSearchDTO();
        roleSearchDTO.setId(roleDTO.getId());
        roleSearchDTO.setRoleName(roleDTO.getRoleName());
        if (roleMapper.countByCondition(roleSearchDTO) >= 1) {
            throw new ApiException(JsonResultEnum.ROLE_NAME_IS_NOT_NULL);
        }
        //接口权限校验
        List<Integer> menuIds = menuMapper.allMenuId();
        List<Integer> addMenuIds = roleDTO.getMenuIds();
        if (!menuIds.containsAll(addMenuIds)) {
            throw new ApiException(JsonResultEnum.MENU_IS_NOT_EXIST);
        }
        Set<Integer> ids = new HashSet<>(addMenuIds);
        roleDTO.setMenuIds(ids.stream().collect(Collectors.toList()));
    }

    /**
     * 删除角色
     *
     * @param id
     * @return com.bsj.travel.def.global.JsonResult
     * @author ljx
     * @time 2024/1/11 17:35
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult deleteRole(Integer id) {
        if (id == null) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        if (roleMapper.selectById(id) == null) {
            return JsonResult.fail(JsonResultEnum.ROLE_IS_NOT_EXIST);
        }
        final String roleId = "roleId";
        if (userMapper.exists(new QueryWrapper<UserDO>().eq(roleId, id))) {
            return JsonResult.fail(JsonResultEnum.FAIL, "此角色与某用户已绑定，无法删除");
        }
        if (roleMapper.deleteById(id) > 0) {
            //删除与权限的关系
            roleMenuMapper.delete(new QueryWrapper<RoleMenuDO>().eq(roleId, id));
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 修改角色
     *
     * @param roleDTO
     * @return com.bsj.travel.def.global.JsonResult
     * @author ljx
     * @time 2024/1/11 17:35
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult updateRole(RoleDTO roleDTO) {
        Integer id = roleDTO.getId();
        if (id == null) {
            return JsonResult.fail(JsonResultEnum.PARAM_ERROR);
        }
        if (roleMapper.selectById(id) == null) {
            return JsonResult.fail(JsonResultEnum.ROLE_IS_NOT_EXIST);
        }
        paramCheck(roleDTO);
        RoleDO roleDO = new RoleDO();
        BeanUtils.copyProperties(roleDTO, roleDO);
        if (roleMapper.updateById(roleDO) > 0) {
            //删除原先的关系
            roleMenuMapper.delete(new QueryWrapper<RoleMenuDO>().eq("roleId", id));
            //添加新的关系
            batchInsertRoleMenu(roleDTO.getMenuIds(), id);
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 根据角色id获取角色信息
     *
     * @param id
     * @return com.bsj.travel.def.common.VO.RoleVO
     * @author ljx
     * @time 2024/1/11 17:36
     */
    @Override
    public RoleVO getRoleInfoById(Integer id) {
        if (id == null) {
            throw new ApiException(JsonResultEnum.PARAM_ERROR);
        }
        RoleDO roleDO = roleMapper.selectById(id);
        if (roleDO == null) {
            throw new ApiException(JsonResultEnum.ROLE_IS_NOT_EXIST);
        }
        RoleVO roleVO = new RoleVO();
        BeanUtils.copyProperties(roleDO, roleVO);
        List<MenuDO> menuDOS = menuMapper.listMenuByRoleId(id);
        roleVO.setMenuDOS(menuDOS);
        return roleVO;
    }

    /**
     * 角色分页
     *
     * @param roleSearchDTO
     * @return com.bsj.travel.def.global.JsonResult<java.util.List < com.bsj.travel.def.common.VO.RoleVO>>
     * @author ljx
     * @time 2024/1/11 17:36
     */
    @Override
    public JsonResult<List<RoleVO>> pageRole(RoleSearchDTO roleSearchDTO) {
        List<RoleVO> roleVOS = roleMapper.selectRolePage(roleSearchDTO);
        if (CollectionUtils.isEmpty(roleVOS)) {
            return JsonResult.success(roleVOS, NumericalConstants.ZERO);
        }
        List<RoleVO> result = DataUtil.pagingByList(roleVOS, roleSearchDTO.getPageSize(), roleSearchDTO.getPageNumber());
        result.forEach(roleVO -> {
            roleVO.setMenuTreeVOS(menuService.structureErection(roleVO.getMenuDOS()));
            roleVO.setMenuDOS(null);
        });
        return JsonResult.success(result, roleVOS.size());
    }
}
